/**
 * Blog post detail page — renders a single published blog post by its slug.
 *
 * - Fetches the post from the Brainerce SDK (returns null on 404)
 * - Generates full SEO metadata (title, description, OG image)
 * - Injects Article JSON-LD for Google rich snippets
 * - Body HTML is sanitized before rendering
 *
 * Security: always pass blog content through sanitizeHtml before dangerouslySetInnerHTML.
 */
import * as React from 'react';
import type { Metadata } from 'next';
import { notFound, permanentRedirect } from 'next/navigation';
import Link from 'next/link';
import { CdnImage as Image } from '@/ui/shared/cdn-image';
import { ArticleJsonLd } from '@/components/seo/article-json-ld';
import { getCanonicalSiteUrl } from '@/core/lib/site-url';

import { getServerClient, fetchStoreInfo } from '@/core/lib/brainerce.server';
import { sanitizeHtml } from '@/core/lib/sanitize';
import { decodeSlug } from '@/core/lib/utils';


<% if (i18nEnabled) { %>
type PageProps = {
  params: Promise<{ locale: string; slug: string }>;
};

export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
  const { locale, slug: rawSlug } = await params;
  const slug = decodeSlug(rawSlug);
  const [post, storeInfo] = await Promise.all([
    (await getServerClient(locale)).blog.getPost(slug).catch(() => null),
    fetchStoreInfo(locale),
  ]);
  if (!post) return { title: slug };

  // Canonical + hreflang. Blog URLs use the same slug across locales (only
  // the locale prefix changes) — the same convention getBlogSitemapEntries
  // emits, so the alternates always match real, crawlable URLs.
  const supportedLocales = storeInfo?.i18n?.supportedLocales ?? [];
  const defaultLoc = storeInfo?.i18n?.defaultLocale ?? storeInfo?.language ?? '';
  const SITE_URL = await getCanonicalSiteUrl();
  const canonicalPath =
    locale && locale !== defaultLoc ? `/${locale}/blog/${post.slug}` : `/blog/${post.slug}`;
  const hreflangLanguages =
    supportedLocales.length > 1
      ? Object.fromEntries([
          ...supportedLocales.map((loc) => [
            loc,
            loc === defaultLoc
              ? `${SITE_URL}/blog/${post.slug}`
              : `${SITE_URL}/${loc}/blog/${post.slug}`,
          ]),
          ['x-default', `${SITE_URL}/blog/${post.slug}`],
        ])
      : undefined;

  return {
    title: post.seoTitle ?? post.title,
    description: post.seoDescription ?? post.excerpt,
    alternates: {
      canonical: canonicalPath,
      ...(hreflangLanguages ? { languages: hreflangLanguages } : {}),
    },
    openGraph: {
      title: post.seoTitle ?? post.title,
      description: post.seoDescription ?? post.excerpt ?? undefined,
      type: 'article',
      publishedTime: post.publishedAt ?? undefined,
      authors: post.author ? [post.author] : undefined,
      images: post.ogImageUrl
        ? [{ url: post.ogImageUrl }]
        : post.coverImageUrl
          ? [{ url: post.coverImageUrl }]
          : undefined,
    },
  };
}

export default async function BlogPostPage({ params }: PageProps) {
  const { locale, slug: rawSlug } = await params;
  const slug = decodeSlug(rawSlug);
  const client = await getServerClient(locale);
  const [post, storeInfo] = await Promise.all([
    // getPost returns null only on a genuine 404; any other API failure (a
    // 403 from the channel's origin check, a network error) throws and
    // surfaces as the error it is instead of masquerading as a missing post.
    client.blog.getPost(slug),
    client.getStoreInfo().catch(() => null),
  ]);
  if (!post) {
    // The slug may have been renamed — 301 to the current slug so the old
    // URL keeps its ranking; genuine unknowns fall through to the 404 page.
    // Default locale stays unprefixed (matches the sitemap/hreflang convention).
    const redirect = await client.resolveSlugRedirect('blog', slug);
    if (redirect) {
      const defaultLoc = storeInfo?.i18n?.defaultLocale ?? storeInfo?.language ?? '';
      const prefix = locale && locale !== defaultLoc ? `/${locale}` : '';
      permanentRedirect(`${prefix}/blog/${redirect.currentSlug}`);
    }
    notFound();
  }

  const isHe = locale === 'he';
  const dir = isHe ? 'rtl' : 'ltr';
  const backLabel = isHe ? '← חזרה לבלוג' : '← Back to blog';
  const SITE_URL = await getCanonicalSiteUrl();
  const articleUrl = `${SITE_URL}/blog/${post.slug}`;

  return (
    <main dir={dir} className="mx-auto max-w-3xl px-4 py-10 sm:px-6 lg:px-8">
      <ArticleJsonLd post={post} url={articleUrl} organizationName={storeInfo?.name} />

      {/* Back link */}
      <Link
        href="/blog"
        className="mb-6 inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground transition-colors"
      >
        {backLabel}
      </Link>

      {/* Category */}
      {post.category && (
        <div className="mb-3">
          <span className="rounded-full bg-primary/10 px-3 py-1 text-xs font-medium text-primary">
            {post.category}
          </span>
        </div>
      )}

      {/* Title */}
      <h1 className="mb-4 text-3xl font-bold tracking-tight text-foreground sm:text-4xl leading-tight">
        {post.title}
      </h1>

      {/* Meta row: author + date + tags */}
      <div className="mb-6 flex flex-wrap items-center gap-x-4 gap-y-2 text-sm text-muted-foreground border-b border-border pb-6">
        {post.author && <span className="font-medium text-foreground">{post.author}</span>}
        {post.publishedAt && (
          <time dateTime={post.publishedAt}>
            {new Date(post.publishedAt).toLocaleDateString(isHe ? 'he-IL' : 'en-US', {
              year: 'numeric',
              month: 'long',
              day: 'numeric',
            })}
          </time>
        )}
        {post.tags && post.tags.length > 0 && (
          <div className="flex flex-wrap gap-1.5">
            {post.tags.map((tag) => (
              <span
                key={tag}
                className="rounded-md bg-muted px-2 py-0.5 text-xs text-muted-foreground"
              >
                {tag}
              </span>
            ))}
          </div>
        )}
      </div>

      {/* Cover image */}
      {post.coverImageUrl && (
        <div className="mb-8 overflow-hidden rounded-xl">
          <Image
            src={post.coverImageUrl}
            alt={post.coverImageAlt ?? post.title}
            width={800}
            height={450}
            className="w-full object-cover"
            priority
          />
        </div>
      )}

      {/* Excerpt */}
      {post.excerpt && (
        <p className="mb-6 text-lg text-muted-foreground leading-relaxed font-light italic border-s-2 border-primary/40 ps-4">
          {post.excerpt}
        </p>
      )}

      {/* Body */}
      <div
        className="prose prose-neutral dark:prose-invert max-w-none"
        dangerouslySetInnerHTML={{ __html: sanitizeHtml(post.content) }}
      />
    </main>
  );
}
<% } else { %>
type PageProps = {
  params: Promise<{ slug: string }>;
};

export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
  const { slug: rawSlug } = await params;
  const slug = decodeSlug(rawSlug);
  const post = await (await getServerClient()).blog.getPost(slug).catch(() => null);
  if (!post) return { title: slug };
  return {
    title: post.seoTitle ?? post.title,
    description: post.seoDescription ?? post.excerpt,
    alternates: { canonical: `/blog/${post.slug}` },
    openGraph: {
      title: post.seoTitle ?? post.title,
      description: post.seoDescription ?? post.excerpt ?? undefined,
      type: 'article',
      publishedTime: post.publishedAt ?? undefined,
      authors: post.author ? [post.author] : undefined,
      images: post.ogImageUrl
        ? [{ url: post.ogImageUrl }]
        : post.coverImageUrl
          ? [{ url: post.coverImageUrl }]
          : undefined,
    },
  };
}

export default async function BlogPostPage({ params }: PageProps) {
  const { slug: rawSlug } = await params;
  const slug = decodeSlug(rawSlug);
  const client = await getServerClient();
  const [post, storeInfo] = await Promise.all([
    // getPost returns null only on a genuine 404; any other API failure (a
    // 403 from the channel's origin check, a network error) throws and
    // surfaces as the error it is instead of masquerading as a missing post.
    client.blog.getPost(slug),
    client.getStoreInfo().catch(() => null),
  ]);
  if (!post) {
    // The slug may have been renamed — 301 to the current slug so the old
    // URL keeps its ranking; genuine unknowns fall through to the 404 page.
    const redirect = await client.resolveSlugRedirect('blog', slug);
    if (redirect) permanentRedirect(`/blog/${redirect.currentSlug}`);
    notFound();
  }

  const SITE_URL = await getCanonicalSiteUrl();
  const articleUrl = `${SITE_URL}/blog/${post.slug}`;

  return (
    <main className="mx-auto max-w-3xl px-4 py-10 sm:px-6 lg:px-8">
      <ArticleJsonLd post={post} url={articleUrl} organizationName={storeInfo?.name} />

      <Link
        href="/blog"
        className="mb-6 inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground transition-colors"
      >
        ← Back to blog
      </Link>

      {post.category && (
        <div className="mb-3">
          <span className="rounded-full bg-primary/10 px-3 py-1 text-xs font-medium text-primary">
            {post.category}
          </span>
        </div>
      )}

      <h1 className="mb-4 text-3xl font-bold tracking-tight text-foreground sm:text-4xl leading-tight">
        {post.title}
      </h1>

      <div className="mb-6 flex flex-wrap items-center gap-x-4 gap-y-2 text-sm text-muted-foreground border-b border-border pb-6">
        {post.author && <span className="font-medium text-foreground">{post.author}</span>}
        {post.publishedAt && (
          <time dateTime={post.publishedAt}>
            {new Date(post.publishedAt).toLocaleDateString('en-US', {
              year: 'numeric',
              month: 'long',
              day: 'numeric',
            })}
          </time>
        )}
        {post.tags && post.tags.length > 0 && (
          <div className="flex flex-wrap gap-1.5">
            {post.tags.map((tag) => (
              <span
                key={tag}
                className="rounded-md bg-muted px-2 py-0.5 text-xs text-muted-foreground"
              >
                {tag}
              </span>
            ))}
          </div>
        )}
      </div>

      {post.coverImageUrl && (
        <div className="mb-8 overflow-hidden rounded-xl">
          <Image
            src={post.coverImageUrl}
            alt={post.coverImageAlt ?? post.title}
            width={800}
            height={450}
            className="w-full object-cover"
            priority
          />
        </div>
      )}

      {post.excerpt && (
        <p className="mb-6 text-lg text-muted-foreground leading-relaxed font-light italic border-s-2 border-primary/40 ps-4">
          {post.excerpt}
        </p>
      )}

      <div
        className="prose prose-neutral dark:prose-invert max-w-none"
        dangerouslySetInnerHTML={{ __html: sanitizeHtml(post.content) }}
      />
    </main>
  );
}
<% } %>
